Candace Savonen - CCDL for ALSF

This notebook is sets up the MAF data files for comparison and does some first line analyses

It is the first notebook in this series which addresses issue # 30 in OpenPBTA.

Usage

To run this from the command line, use:

Rscript -e "rmarkdown::render('analyses/mutect2-vs-strelka2/01-set-up.Rmd', 
                              clean = TRUE)"

This assumes you are in the top directory of the repository.

Set Up

# We need maftools - this will be added to the running Docker issue whenever it is up
if (!('maftools' %in% installed.packages())) {
  devtools::install_github("PoisonAlien/maftools")
}

if (!('hexbin' %in% installed.packages())) {
  install.packages("hexbin")
}

if (!('colorblindr' %in% installed.packages())) {
  devtools::install_github("clauswilke/colorblindr")
}

Get magrittr pipe

`%>%` <- dplyr::`%>%`

Directories and files

Path to the symlinked data obtained via bash download-data.sh.

data_dir <- file.path("..", "..", "data")
scratch_dir <- file.path("..", "..", "scratch")

Create output directories in this analysis folder.

if (!dir.exists("results")) {
  dir.create("results")
}
if (!dir.exists("plots")) {
  dir.create("plots")
}

Read in the metadata information

Running maftools::read.maf takes a lot of computing power and time, so to avoid having to run this for both datasets everytime we want to re-run this notebook or the analyses in the other notebook, I’ve set this up to save the MAF objects as RDS files.

First let’s establish the file paths.

# File paths for the needed files for this analysis
metadata_dir <- file.path(scratch_dir, "metadata_filtered_maf_samples.tsv")
strelka2_dir <- file.path(scratch_dir, "strelka2.RDS")
mutect2_dir <- file.path(scratch_dir, "mutect2.RDS")

Read in the Strelka2 and Mutect2 data

Will read in as an maftools object from an RDS file, unless maftools has not been run on them yet. Establish whether the files we need for this already exist before running it again.

If you trying to run the set up step in a Docker container, it will likely be out of memory killed, unless you have ~50GB you can allot to Docker.

Prep the metadata to be used as the clinicalData for maftools it it hasn’t been prepped yet.

# Get a vector of whether these exist
files_needed <- file.exists(metadata_dir, strelka2_dir, mutect2_dir)
Error in file.exists(metadata_dir, strelka2_dir, mutect2_dir) : 
  object 'metadata_dir' not found

Get summaries and write them to TSVs

Get gene summaries and write to TSV files.

strelka2_gene_sum <- maftools::getGeneSummary(strelka2) %>% 
  readr::write_tsv(file.path("results", 
                             "strelka2_gene_summary.tsv"))

mutect2_gene_sum <- maftools::getGeneSummary(mutect2) %>% 
  readr::write_tsv(file.path("results", 
                             "mutect2_gene_summary.tsv"))

Get sample summaries and write to TSV files.

strelka2_sample_sum <- maftools::getSampleSummary(strelka2) %>% 
  readr::write_tsv(file.path("results", 
                             "strelka2_sample_summary.tsv"))

mutect2_sample_sum <- maftools::getSampleSummary(mutect2) %>% 
  readr::write_tsv(file.path("results", 
                             "mutect2_sample_summary.tsv"))

Number of mutations per gene correlation

combined_gene <- mutect2_gene_sum %>% 
  dplyr::full_join(strelka2_gene_sum, by = 'Hugo_Symbol') %>%
  reshape2::melt(id = 'Hugo_Symbol') %>% 
  dplyr::mutate(dataset = as.character(grepl(".x$", variable))) %>%
  dplyr::mutate(dataset = dplyr::recode(dataset, 
                                        `TRUE` = "mutect2", 
                                        `FALSE` = "strelka2")) %>%
  dplyr::mutate(variable = gsub(".x$|.y$", "", variable)) %>% 
  tidyr::spread('dataset', 'value')

Let’s get a correlation test on the genes overall.

cor.test(combined_gene$mutect2, combined_gene$strelka2, method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  combined_gene$mutect2 and combined_gene$strelka2
S = 4.8562e+13, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.9550336 
cor.test(combined_gene$mutect2, combined_gene$strelka2, method = "pearson")

    Pearson's product-moment correlation

data:  combined_gene$mutect2 and combined_gene$strelka2
t = 563.23, df = 186430, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.7919415 0.7953020
sample estimates:
      cor 
0.7936278 

Number of mutations per sample correlation.

combined_sample <- mutect2_sample_sum %>% 
  dplyr::full_join(strelka2_sample_sum, by = 'Tumor_Sample_Barcode') %>%
  reshape2::melt(id = 'Tumor_Sample_Barcode') %>% 
  dplyr::mutate(dataset = as.character(grepl(".x$", variable))) %>%
  dplyr::mutate(dataset = dplyr::recode(dataset, 
                                        `TRUE` = "mutect2", 
                                        `FALSE` = "strelka2")) %>%
  dplyr::mutate(variable = gsub(".x$|.y$", "", variable)) %>% 
  tidyr::spread('dataset', 'value')

Let’s get a correlation test on the genes overall.

cor.test(combined_sample$mutect2, combined_sample$strelka2, method = "spearman")
Cannot compute exact p-value with ties

    Spearman's rank correlation rho

data:  combined_sample$mutect2 and combined_sample$strelka2
S = 2.6957e+10, p-value < 2.2e-16
alternative hypothesis: true rho is not equal to 0
sample estimates:
      rho 
0.7758976 
cor.test(combined_sample$mutect2, combined_sample$strelka2, method = "pearson")

    Pearson's product-moment correlation

data:  combined_sample$mutect2 and combined_sample$strelka2
t = 750.22, df = 8968, p-value < 2.2e-16
alternative hypothesis: true correlation is not equal to 0
95 percent confidence interval:
 0.9917956 0.9924450
sample estimates:
     cor 
0.992127 

Plot Transition/Transversions

maftools::plotTiTv(maftools::titv(mutect2))

Set up new variables

Here we will make these new variables for both Mutect2 and Strelka2 dataset: - Calculate VAF for each - Make a mutation ID by concatenating gene name, allele, tumor ID, and start position - Summarize the biotype variable for whether or not it is a coding gene.

Let’s do this for Strelka2 first.

strelka2_vaf <- strelka2@data %>%
  dplyr::mutate(vaf = as.numeric(t_alt_count)/(as.numeric(t_ref_count) + 
                                                 as.numeric(t_alt_count)),
                base_change = paste0(Reference_Allele, ">", Allele), 
                coding = dplyr::case_when( 
                  BIOTYPE != "protein_coding" ~ "non-coding",
                  TRUE ~ "protein_coding")) %>%
    dplyr::mutate(change = dplyr::case_when(
      grepl("^-", base_change) ~ "insertion",
      grepl("-$", base_change) ~ "deletion",
      nchar(base_change) > 3 ~ "long_change",
      TRUE ~ base_change)) %>%
    dplyr::mutate(mutation_id = paste0(Hugo_Symbol, "_", 
                                       change, "_", 
                                       Start_Position, "_",
                                       Tumor_Sample_Barcode),
                  general_id = paste0(Hugo_Symbol, "_", Tumor_Sample_Barcode)) %>%
    dplyr::select(-which(apply(is.na(.), 2, all)))
NAs introduced by coercion
# Take a look at this df
strelka2_vaf  

Now we will do the same for MuTect2.

mutect2_vaf <- mutect2@data %>%
  dplyr::mutate(vaf = as.numeric(t_alt_count)/(as.numeric(t_ref_count) + 
                                                 as.numeric(t_alt_count)),
                base_change = paste0(Reference_Allele, ">", Allele), 
                coding = dplyr::case_when(
                  BIOTYPE != "protein_coding" ~ "non-coding",
                  TRUE ~ "protein_coding")) %>%
    dplyr::mutate(change = dplyr::case_when( 
      grepl("^-", base_change) ~ "insertion",
      grepl("-$", base_change) ~ "deletion",
      nchar(base_change) > 3 ~ "long_change",
      TRUE ~ base_change)) %>%
    dplyr::mutate(mutation_id = paste0(Hugo_Symbol, "_", 
                                       change, "_", 
                                       Start_Position, "_",
                                       Tumor_Sample_Barcode),
                  general_id = paste0(Hugo_Symbol, "_", Tumor_Sample_Barcode)) %>%
    dplyr::select(-which(apply(is.na(.), 2, all)))

# Take a look at this df
mutect2_vaf

Combine MuTect2 and Strelka2 data.frames into one data.frame

Save to a TSV file.

# Merge these data.frames together
vaf_df <- strelka2_vaf %>%
  dplyr::full_join(mutect2_vaf, by = 'mutation_id', 
                    suffix = c(".strelka2", ".mutect2")) %>%
  # Make a variable that denotes which dataset it is in.
  dplyr::mutate(dataset = dplyr::case_when( 
    is.na(Allele.mutect2) ~ "strelka2_only",
    is.na(Allele.strelka2) ~ "mutect2_only", 
    TRUE ~ "both")) %>%
  readr::write_tsv(file.path("results", "combined_results.tsv"))

Session Info:

sessionInfo()
R version 3.6.1 (2019-07-05)
Platform: x86_64-apple-darwin15.6.0 (64-bit)
Running under: macOS Mojave 10.14.5

Matrix products: default
BLAS:   /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
LAPACK: /Library/Frameworks/R.framework/Versions/3.6/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] parallel  stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
[1] Biobase_2.44.0      BiocGenerics_0.30.0

loaded via a namespace (and not attached):
 [1] fs_1.3.1             usethis_1.5.1        devtools_2.1.0       doParallel_1.0.15    RColorBrewer_1.1-2  
 [6] rprojroot_1.3-2      tools_3.6.1          backports_1.1.4      utf8_1.1.4           R6_2.4.0            
[11] lazyeval_0.2.2       colorspace_1.4-1     withr_2.1.2          tidyselect_0.2.5     prettyunits_1.0.2   
[16] processx_3.4.1       compiler_3.6.1       VennDiagram_1.6.20   cli_1.1.0            formatR_1.7         
[21] desc_1.2.0           pkgmaker_0.27        labeling_0.3         scales_1.0.0         hexbin_1.27.3       
[26] readr_1.3.1          callr_3.3.1          NMF_0.21.0           stringr_1.4.0        digest_0.6.20       
[31] rmarkdown_1.14       R.utils_2.9.0        base64enc_0.1-3      pkgconfig_2.0.2      htmltools_0.3.6     
[36] bibtex_0.4.2         sessioninfo_1.1.1    rlang_0.4.0          rstudioapi_0.10      jsonlite_1.6        
[41] dplyr_0.8.3          R.oo_1.22.0          magrittr_1.5         wordcloud_2.6        futile.logger_1.4.3 
[46] Matrix_1.2-17        Rcpp_1.0.2           munsell_0.5.0        fansi_0.4.0          R.methodsS3_1.7.1   
[51] stringi_1.4.3        yaml_2.2.0           pkgbuild_1.0.4       plyr_1.8.4           grid_3.6.1          
[56] crayon_1.3.4         lattice_0.20-38      splines_3.6.1        hms_0.5.0            zeallot_0.1.0       
[61] knitr_1.24           ps_1.3.0             pillar_1.4.2         rngtools_1.4         reshape2_1.4.3      
[66] codetools_0.2-16     pkgload_1.0.2        futile.options_1.0.1 glue_1.3.1           evaluate_0.14       
[71] lambda.r_1.2.3       data.table_1.12.2    remotes_2.1.0        BiocManager_1.30.4   colorblindr_0.1.0   
[76] vctrs_0.2.0          foreach_1.4.7        testthat_2.2.1       gtable_0.3.0         purrr_0.3.2         
[81] tidyr_0.8.3          assertthat_0.2.1     ggplot2_3.2.1        xfun_0.8             gridBase_0.4-7      
[86] xtable_1.8-4         survival_2.44-1.1    tibble_2.1.3         iterators_1.0.12     registry_0.5-1      
[91] memoise_1.1.0        maftools_2.0.15      cluster_2.1.0       
LS0tCnRpdGxlOiAiRXZhbHVhdGUgY29uY29yZGFuY2UgYmV0d2VlbiBNdXRlY3QyIGFuZCBTdHJlbGthMiIKb3V0cHV0OiAgIAogIGh0bWxfbm90ZWJvb2s6IAogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpDYW5kYWNlIFNhdm9uZW4gLSBDQ0RMIGZvciBBTFNGCgpUaGlzIG5vdGVib29rIGlzIHNldHMgdXAgdGhlIE1BRiBkYXRhIGZpbGVzIGZvciBjb21wYXJpc29uIGFuZCBkb2VzIHNvbWUgZmlyc3QgCmxpbmUgYW5hbHlzZXMKCkl0IGlzIHRoZSBmaXJzdCBub3RlYm9vayBpbiB0aGlzIHNlcmllcyB3aGljaCBhZGRyZXNzZXMgW2lzc3VlIFwjIDMwIGluIE9wZW5QQlRBXShodHRwczovL2dpdGh1Yi5jb20vQWxleHNMZW1vbmFkZS9PcGVuUEJUQS1hbmFseXNpcy9pc3N1ZXMvMzApLgoKIyMgVXNhZ2UKClRvIHJ1biB0aGlzIGZyb20gdGhlIGNvbW1hbmQgbGluZSwgdXNlOgpgYGAKUnNjcmlwdCAtZSAicm1hcmtkb3duOjpyZW5kZXIoJ2FuYWx5c2VzL211dGVjdDItdnMtc3RyZWxrYTIvMDEtc2V0LXVwLlJtZCcsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGVhbiA9IFRSVUUpIgpgYGAKCiBfVGhpcyBhc3N1bWVzIHlvdSBhcmUgaW4gdGhlIHRvcCBkaXJlY3Rvcnkgb2YgdGhlIHJlcG9zaXRvcnkuXwoKIyMgU2V0IFVwCgpgYGB7cn0KIyBXZSBuZWVkIG1hZnRvb2xzIC0gdGhpcyB3aWxsIGJlIGFkZGVkIHRvIHRoZSBydW5uaW5nIERvY2tlciBpc3N1ZSB3aGVuZXZlciBpdCBpcyB1cAppZiAoISgnbWFmdG9vbHMnICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSB7CiAgZGV2dG9vbHM6Omluc3RhbGxfZ2l0aHViKCJQb2lzb25BbGllbi9tYWZ0b29scyIpCn0KCmlmICghKCdoZXhiaW4nICVpbiUgaW5zdGFsbGVkLnBhY2thZ2VzKCkpKSB7CiAgaW5zdGFsbC5wYWNrYWdlcygiaGV4YmluIikKfQoKaWYgKCEoJ2NvbG9yYmxpbmRyJyAlaW4lIGluc3RhbGxlZC5wYWNrYWdlcygpKSkgewogIGRldnRvb2xzOjppbnN0YWxsX2dpdGh1YigiY2xhdXN3aWxrZS9jb2xvcmJsaW5kciIpCn0KYGBgCgpHZXQgYG1hZ3JpdHRyYCBwaXBlCgpgYGB7cn0KYCU+JWAgPC0gZHBseXI6OmAlPiVgCmBgYAoKIyMjIERpcmVjdG9yaWVzIGFuZCBmaWxlcwoKUGF0aCB0byB0aGUgc3ltbGlua2VkIGRhdGEgb2J0YWluZWQgdmlhIGBiYXNoIGRvd25sb2FkLWRhdGEuc2hgLgoKYGBge3J9CmRhdGFfZGlyIDwtIGZpbGUucGF0aCgiLi4iLCAiLi4iLCAiZGF0YSIpCnNjcmF0Y2hfZGlyIDwtIGZpbGUucGF0aCgiLi4iLCAiLi4iLCAic2NyYXRjaCIpCmBgYAoKQ3JlYXRlIG91dHB1dCBkaXJlY3RvcmllcyBpbiB0aGlzIGFuYWx5c2lzIGZvbGRlci4KCmBgYHtyfQppZiAoIWRpci5leGlzdHMoInJlc3VsdHMiKSkgewogIGRpci5jcmVhdGUoInJlc3VsdHMiKQp9CmlmICghZGlyLmV4aXN0cygicGxvdHMiKSkgewogIGRpci5jcmVhdGUoInBsb3RzIikKfQpgYGAKCiMjIFJlYWQgaW4gdGhlIG1ldGFkYXRhIGluZm9ybWF0aW9uCgpSdW5uaW5nIGBtYWZ0b29sczo6cmVhZC5tYWZgIHRha2VzIGEgbG90IG9mIGNvbXB1dGluZyBwb3dlciBhbmQgdGltZSwgc28gdG8gCmF2b2lkIGhhdmluZyB0byBydW4gdGhpcyBmb3IgYm90aCBkYXRhc2V0cyBldmVyeXRpbWUgd2Ugd2FudCB0byByZS1ydW4gdGhpcyAKbm90ZWJvb2sgb3IgdGhlIGFuYWx5c2VzIGluIHRoZSBvdGhlciBub3RlYm9vaywgSSd2ZSBzZXQgdGhpcyB1cCB0byBzYXZlIHRoZSAKYE1BRmAgb2JqZWN0cyBhcyBgUkRTYCBmaWxlcy4KCkZpcnN0IGxldCdzIGVzdGFibGlzaCB0aGUgZmlsZSBwYXRocy4KCmBgYHtyfQojIEZpbGUgcGF0aHMgZm9yIHRoZSBuZWVkZWQgZmlsZXMgZm9yIHRoaXMgYW5hbHlzaXMKbWV0YWRhdGFfZGlyIDwtIGZpbGUucGF0aChzY3JhdGNoX2RpciwgIm1ldGFkYXRhX2ZpbHRlcmVkX21hZl9zYW1wbGVzLnRzdiIpCnN0cmVsa2EyX2RpciA8LSBmaWxlLnBhdGgoc2NyYXRjaF9kaXIsICJzdHJlbGthMi5SRFMiKQptdXRlY3QyX2RpciA8LSBmaWxlLnBhdGgoc2NyYXRjaF9kaXIsICJtdXRlY3QyLlJEUyIpCmBgYAoKIyMgUmVhZCBpbiB0aGUgU3RyZWxrYTIgYW5kIE11dGVjdDIgZGF0YQoKV2lsbCByZWFkIGluIGFzIGFuIGBtYWZ0b29sc2Agb2JqZWN0IGZyb20gYW4gUkRTIGZpbGUsIHVubGVzcyBgbWFmdG9vbHNgIGhhcyBub3QgYmVlbiAKcnVuIG9uIHRoZW0geWV0LgpFc3RhYmxpc2ggd2hldGhlciB0aGUgZmlsZXMgd2UgbmVlZCBmb3IgdGhpcyBhbHJlYWR5IGV4aXN0IGJlZm9yZSBydW5uaW5nIGl0IAphZ2Fpbi4gCgpJZiB5b3UgdHJ5aW5nIHRvIHJ1biB0aGUgc2V0IHVwIHN0ZXAgaW4gYSBEb2NrZXIgY29udGFpbmVyLCBpdCB3aWxsIGxpa2VseSBiZSAKb3V0IG9mIG1lbW9yeSBraWxsZWQsIHVubGVzcyB5b3UgaGF2ZSB+NTBHQiB5b3UgY2FuIGFsbG90IHRvIERvY2tlci4gCgpQcmVwIHRoZSBtZXRhZGF0YSB0byBiZSB1c2VkIGFzIHRoZSBgY2xpbmljYWxEYXRhYCBmb3IgbWFmdG9vbHMgaXQgaXQgaGFzbid0IGJlZW4gCnByZXBwZWQgeWV0LiAKCmBgYHtyfQojIEdldCBhIHZlY3RvciBvZiB3aGV0aGVyIHRoZXNlIGV4aXN0CmZpbGVzX25lZWRlZCA8LSBmaWxlLmV4aXN0cyhtZXRhZGF0YV9kaXIsIHN0cmVsa2EyX2RpciwgbXV0ZWN0Ml9kaXIpCgppZiAoYWxsKGZpbGVzX25lZWRlZCkpIHsKICAjIFJlYWQgdGhlIHJlYWR5LXRvLWdvIGZpbGVzIGlmIHRoZXNlIGZpbGVzIGV4aXN0CiAgbWV0YWRhdGEgPC0gICBtZXRhZGF0YSA8LSByZWFkcjo6cmVhZF90c3YobWV0YWRhdGFfZGlyKQogIHN0cmVsa2EyIDwtIHJlYWRSRFMoc3RyZWxrYTJfZGlyKQogIG11dGVjdDIgPC0gcmVhZFJEUyhtdXRlY3QyX2RpcikKICAKfSBlbHNlIHsgIyBJZiBhbnkgb2YgdGhlIG5lZWRlZCBmaWxlcyBkb24ndCBleGlzdCwgcmVydW4gdGhpcyBwcm9jZXNzOiAKICAjIE9ubHkgaW1wb3J0IHRoZSBzYW1wbGUgbmFtZXMgCiAgc3RyZWxrYTJfc2FtcGxlcyA8LSBkYXRhLnRhYmxlOjpmcmVhZChmaWxlLnBhdGgoZGF0YV9kaXIsICJwYnRhLXNudi1zdHJlbGthMi52ZXAubWFmLmd6IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2VsZWN0ID0gIlR1bW9yX1NhbXBsZV9CYXJjb2RlIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgc2tpcCA9IDEsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhdGEudGFibGUgPSBGQUxTRSkKCiAgbXV0ZWN0Ml9zYW1wbGVzIDwtIGRhdGEudGFibGU6OmZyZWFkKGZpbGUucGF0aChkYXRhX2RpciwgInBidGEtc252LW11dGVjdDIudmVwLm1hZi5neiIpLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNlbGVjdCA9ICJUdW1vcl9TYW1wbGVfQmFyY29kZSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIHNraXAgPSAxLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkYXRhLnRhYmxlID0gRkFMU0UpCgogICMgSXNvbGF0ZSBtZXRhZGF0YSB0byBvbmx5IHRoZSBzYW1wbGVzIHRoYXQgYXJlIGluIHRoZSBkYXRhc2V0cwogIG1ldGFkYXRhIDwtIHJlYWRyOjpyZWFkX3RzdihkYXRhX2RpciwgInBidGEtaGlzdG9sb2dpZXMudHN2IikgJT4lCiAgICBkcGx5cjo6ZmlsdGVyKEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQgJWluJSBjKHN0cmVsa2EyX3NhbXBsZXMsIG11dGVjdDJfc2FtcGxlcykpICU+JQogICAgZHBseXI6OmRpc3RpbmN0KEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQsIC5rZWVwX2FsbCA9IFRSVUUpICU+JQogICAgZHBseXI6OmFycmFuZ2UoKSAlPiUKICAgIHJlYWRyOjp3cml0ZV90c3YoZmlsZS5wYXRoKHNjcmF0Y2hfZGlyLCAibWV0YWRhdGFfZmlsdGVyZWRfbWFmX3NhbXBsZXMudHN2IikpCiAgCiAgIyBSZWFkIGluIG9yaWdpbmFsIHN0cmVsa2EgZmlsZSB3aXRoIG1hZnRvb2xzCiAgc3RyZWxrYSA8LSBtYWZ0b29sczo6cmVhZC5tYWYoZmlsZS5wYXRoKGRhdGFfZGlyLCAicGJ0YS1zbnYtc3RyZWxrYTIudmVwLm1hZi5neiIpLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjbGluaWNhbERhdGEgPSBtZXRhZGF0YSkKICAKICAjIFNhdmUgdG8gUkRTIHNvIHdlIGRvbid0IGhhdmUgdG8gcnVuIHRoaXMgYWdhaW4KICBzYXZlUkRTKHN0cmVsa2EsIHN0cmVsa2EyX2RpcikKCiAgIyBTYW1lIGZvciBNdVRlY3QyCiAgbXV0ZWN0MiA8LSBtYWZ0b29sczo6cmVhZC5tYWYoZmlsZS5wYXRoKGRhdGFfZGlyLCAicGJ0YS1zbnYtbXV0ZWN0Mi52ZXAubWFmLmd6IiksCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2xpbmljYWxEYXRhID0gbWV0YWRhdGEpCiAgc2F2ZVJEUyhtdXRlY3QyLCBtdXRlY3QyX2RpcikKfQpgYGAKCiMjIEdldCBzdW1tYXJpZXMgYW5kIHdyaXRlIHRoZW0gdG8gVFNWcyAKCkdldCBnZW5lIHN1bW1hcmllcyBhbmQgd3JpdGUgdG8gVFNWIGZpbGVzLiAKCmBgYHtyfQpzdHJlbGthMl9nZW5lX3N1bSA8LSBtYWZ0b29sczo6Z2V0R2VuZVN1bW1hcnkoc3RyZWxrYTIpICU+JSAKICByZWFkcjo6d3JpdGVfdHN2KGZpbGUucGF0aCgicmVzdWx0cyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJzdHJlbGthMl9nZW5lX3N1bW1hcnkudHN2IikpCgptdXRlY3QyX2dlbmVfc3VtIDwtIG1hZnRvb2xzOjpnZXRHZW5lU3VtbWFyeShtdXRlY3QyKSAlPiUgCiAgcmVhZHI6OndyaXRlX3RzdihmaWxlLnBhdGgoInJlc3VsdHMiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAibXV0ZWN0Ml9nZW5lX3N1bW1hcnkudHN2IikpCmBgYAoKR2V0IHNhbXBsZSBzdW1tYXJpZXMgYW5kIHdyaXRlIHRvIFRTViBmaWxlcy4gCgpgYGB7cn0Kc3RyZWxrYTJfc2FtcGxlX3N1bSA8LSBtYWZ0b29sczo6Z2V0U2FtcGxlU3VtbWFyeShzdHJlbGthMikgJT4lIAogIHJlYWRyOjp3cml0ZV90c3YoZmlsZS5wYXRoKCJyZXN1bHRzIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgInN0cmVsa2EyX3NhbXBsZV9zdW1tYXJ5LnRzdiIpKQoKbXV0ZWN0Ml9zYW1wbGVfc3VtIDwtIG1hZnRvb2xzOjpnZXRTYW1wbGVTdW1tYXJ5KG11dGVjdDIpICU+JSAKICByZWFkcjo6d3JpdGVfdHN2KGZpbGUucGF0aCgicmVzdWx0cyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICJtdXRlY3QyX3NhbXBsZV9zdW1tYXJ5LnRzdiIpKQpgYGAKCiMjIE51bWJlciBvZiBtdXRhdGlvbnMgcGVyIGdlbmUgY29ycmVsYXRpb24gCgpgYGB7cn0KY29tYmluZWRfZ2VuZSA8LSBtdXRlY3QyX2dlbmVfc3VtICU+JSAKICBkcGx5cjo6ZnVsbF9qb2luKHN0cmVsa2EyX2dlbmVfc3VtLCBieSA9ICdIdWdvX1N5bWJvbCcpICU+JQogIHJlc2hhcGUyOjptZWx0KGlkID0gJ0h1Z29fU3ltYm9sJykgJT4lIAogIGRwbHlyOjptdXRhdGUoZGF0YXNldCA9IGFzLmNoYXJhY3RlcihncmVwbCgiLngkIiwgdmFyaWFibGUpKSkgJT4lCiAgZHBseXI6Om11dGF0ZShkYXRhc2V0ID0gZHBseXI6OnJlY29kZShkYXRhc2V0LCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGBUUlVFYCA9ICJtdXRlY3QyIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgRkFMU0VgID0gInN0cmVsa2EyIikpICU+JQogIGRwbHlyOjptdXRhdGUodmFyaWFibGUgPSBnc3ViKCIueCR8LnkkIiwgIiIsIHZhcmlhYmxlKSkgJT4lIAogIHRpZHlyOjpzcHJlYWQoJ2RhdGFzZXQnLCAndmFsdWUnKQpgYGAKCkxldCdzIGdldCBhIGNvcnJlbGF0aW9uIHRlc3Qgb24gdGhlIGdlbmVzIG92ZXJhbGwuCgpgYGB7cn0KY29yLnRlc3QoY29tYmluZWRfZ2VuZSRtdXRlY3QyLCBjb21iaW5lZF9nZW5lJHN0cmVsa2EyLCBtZXRob2QgPSAic3BlYXJtYW4iKQpjb3IudGVzdChjb21iaW5lZF9nZW5lJG11dGVjdDIsIGNvbWJpbmVkX2dlbmUkc3RyZWxrYTIsIG1ldGhvZCA9ICJwZWFyc29uIikKYGBgCgojIyBOdW1iZXIgb2YgbXV0YXRpb25zIHBlciBzYW1wbGUgY29ycmVsYXRpb24uIAoKYGBge3J9CmNvbWJpbmVkX3NhbXBsZSA8LSBtdXRlY3QyX3NhbXBsZV9zdW0gJT4lIAogIGRwbHlyOjpmdWxsX2pvaW4oc3RyZWxrYTJfc2FtcGxlX3N1bSwgYnkgPSAnVHVtb3JfU2FtcGxlX0JhcmNvZGUnKSAlPiUKICByZXNoYXBlMjo6bWVsdChpZCA9ICdUdW1vcl9TYW1wbGVfQmFyY29kZScpICU+JSAKICBkcGx5cjo6bXV0YXRlKGRhdGFzZXQgPSBhcy5jaGFyYWN0ZXIoZ3JlcGwoIi54JCIsIHZhcmlhYmxlKSkpICU+JQogIGRwbHlyOjptdXRhdGUoZGF0YXNldCA9IGRwbHlyOjpyZWNvZGUoZGF0YXNldCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBgVFJVRWAgPSAibXV0ZWN0MiIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYEZBTFNFYCA9ICJzdHJlbGthMiIpKSAlPiUKICBkcGx5cjo6bXV0YXRlKHZhcmlhYmxlID0gZ3N1YigiLngkfC55JCIsICIiLCB2YXJpYWJsZSkpICU+JSAKICB0aWR5cjo6c3ByZWFkKCdkYXRhc2V0JywgJ3ZhbHVlJykKYGBgCgpMZXQncyBnZXQgYSBjb3JyZWxhdGlvbiB0ZXN0IG9uIHRoZSBnZW5lcyBvdmVyYWxsLgoKYGBge3J9CmNvci50ZXN0KGNvbWJpbmVkX3NhbXBsZSRtdXRlY3QyLCBjb21iaW5lZF9zYW1wbGUkc3RyZWxrYTIsIG1ldGhvZCA9ICJzcGVhcm1hbiIpCmNvci50ZXN0KGNvbWJpbmVkX3NhbXBsZSRtdXRlY3QyLCBjb21iaW5lZF9zYW1wbGUkc3RyZWxrYTIsIG1ldGhvZCA9ICJwZWFyc29uIikKYGBgCgojIyBQbG90IFRyYW5zaXRpb24vVHJhbnN2ZXJzaW9ucwoKYGBge3J9Cm1hZnRvb2xzOjpwbG90VGlUdihtYWZ0b29sczo6dGl0dihzdHJlbGthMikpCmBgYAoKYGBge3J9Cm1hZnRvb2xzOjpwbG90VGlUdihtYWZ0b29sczo6dGl0dihtdXRlY3QyKSkKYGBgCgojIyBTZXQgdXAgbmV3IHZhcmlhYmxlcwoKSGVyZSB3ZSB3aWxsIG1ha2UgdGhlc2UgbmV3IHZhcmlhYmxlcyBmb3IgYm90aCBNdXRlY3QyIGFuZCBTdHJlbGthMiBkYXRhc2V0OgotIENhbGN1bGF0ZSBWQUYgZm9yIGVhY2gKLSBNYWtlIGEgbXV0YXRpb24gSUQgYnkgY29uY2F0ZW5hdGluZyBnZW5lIG5hbWUsIGFsbGVsZSwgdHVtb3IgSUQsIGFuZCBzdGFydCBwb3NpdGlvbgotIFN1bW1hcml6ZSB0aGUgYmlvdHlwZSB2YXJpYWJsZSBmb3Igd2hldGhlciBvciBub3QgaXQgaXMgYSBjb2RpbmcgZ2VuZS4gCgpMZXQncyBkbyB0aGlzIGZvciBTdHJlbGthMiBmaXJzdC4gCgpgYGB7cn0Kc3RyZWxrYTJfdmFmIDwtIHN0cmVsa2EyQGRhdGEgJT4lCiAgZHBseXI6Om11dGF0ZSh2YWYgPSBhcy5udW1lcmljKHRfYWx0X2NvdW50KS8oYXMubnVtZXJpYyh0X3JlZl9jb3VudCkgKyAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGFzLm51bWVyaWModF9hbHRfY291bnQpKSwKICAgICAgICAgICAgICAgIGJhc2VfY2hhbmdlID0gcGFzdGUwKFJlZmVyZW5jZV9BbGxlbGUsICI+IiwgQWxsZWxlKSwgCiAgICAgICAgICAgICAgICBjb2RpbmcgPSBkcGx5cjo6Y2FzZV93aGVuKCAKICAgICAgICAgICAgICAgICAgQklPVFlQRSAhPSAicHJvdGVpbl9jb2RpbmciIH4gIm5vbi1jb2RpbmciLAogICAgICAgICAgICAgICAgICBUUlVFIH4gInByb3RlaW5fY29kaW5nIikpICU+JQogICAgZHBseXI6Om11dGF0ZShjaGFuZ2UgPSBkcGx5cjo6Y2FzZV93aGVuKAogICAgICBncmVwbCgiXi0iLCBiYXNlX2NoYW5nZSkgfiAiaW5zZXJ0aW9uIiwKICAgICAgZ3JlcGwoIi0kIiwgYmFzZV9jaGFuZ2UpIH4gImRlbGV0aW9uIiwKICAgICAgbmNoYXIoYmFzZV9jaGFuZ2UpID4gMyB+ICJsb25nX2NoYW5nZSIsCiAgICAgIFRSVUUgfiBiYXNlX2NoYW5nZSkpICU+JQogICAgZHBseXI6Om11dGF0ZShtdXRhdGlvbl9pZCA9IHBhc3RlMChIdWdvX1N5bWJvbCwgIl8iLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgY2hhbmdlLCAiXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBTdGFydF9Qb3NpdGlvbiwgIl8iLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBUdW1vcl9TYW1wbGVfQmFyY29kZSksCiAgICAgICAgICAgICAgICAgIGdlbmVyYWxfaWQgPSBwYXN0ZTAoSHVnb19TeW1ib2wsICJfIiwgVHVtb3JfU2FtcGxlX0JhcmNvZGUpKSAlPiUKICAgIGRwbHlyOjpzZWxlY3QoLXdoaWNoKGFwcGx5KGlzLm5hKC4pLCAyLCBhbGwpKSkKCiMgVGFrZSBhIGxvb2sgYXQgdGhpcyBkZgpzdHJlbGthMl92YWYgIApgYGAKCk5vdyB3ZSB3aWxsIGRvIHRoZSBzYW1lIGZvciBNdVRlY3QyLgoKYGBge3J9Cm11dGVjdDJfdmFmIDwtIG11dGVjdDJAZGF0YSAlPiUKICBkcGx5cjo6bXV0YXRlKHZhZiA9IGFzLm51bWVyaWModF9hbHRfY291bnQpLyhhcy5udW1lcmljKHRfcmVmX2NvdW50KSArIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYXMubnVtZXJpYyh0X2FsdF9jb3VudCkpLAogICAgICAgICAgICAgICAgYmFzZV9jaGFuZ2UgPSBwYXN0ZTAoUmVmZXJlbmNlX0FsbGVsZSwgIj4iLCBBbGxlbGUpLCAKICAgICAgICAgICAgICAgIGNvZGluZyA9IGRwbHlyOjpjYXNlX3doZW4oCiAgICAgICAgICAgICAgICAgIEJJT1RZUEUgIT0gInByb3RlaW5fY29kaW5nIiB+ICJub24tY29kaW5nIiwKICAgICAgICAgICAgICAgICAgVFJVRSB+ICJwcm90ZWluX2NvZGluZyIpKSAlPiUKICAgIGRwbHlyOjptdXRhdGUoY2hhbmdlID0gZHBseXI6OmNhc2Vfd2hlbiggCiAgICAgIGdyZXBsKCJeLSIsIGJhc2VfY2hhbmdlKSB+ICJpbnNlcnRpb24iLAogICAgICBncmVwbCgiLSQiLCBiYXNlX2NoYW5nZSkgfiAiZGVsZXRpb24iLAogICAgICBuY2hhcihiYXNlX2NoYW5nZSkgPiAzIH4gImxvbmdfY2hhbmdlIiwKICAgICAgVFJVRSB+IGJhc2VfY2hhbmdlKSkgJT4lCiAgICBkcGx5cjo6bXV0YXRlKG11dGF0aW9uX2lkID0gcGFzdGUwKEh1Z29fU3ltYm9sLCAiXyIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjaGFuZ2UsICJfIiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFN0YXJ0X1Bvc2l0aW9uLCAiXyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIFR1bW9yX1NhbXBsZV9CYXJjb2RlKSwKICAgICAgICAgICAgICAgICAgZ2VuZXJhbF9pZCA9IHBhc3RlMChIdWdvX1N5bWJvbCwgIl8iLCBUdW1vcl9TYW1wbGVfQmFyY29kZSkpICU+JQogICAgZHBseXI6OnNlbGVjdCgtd2hpY2goYXBwbHkoaXMubmEoLiksIDIsIGFsbCkpKQoKIyBUYWtlIGEgbG9vayBhdCB0aGlzIGRmCm11dGVjdDJfdmFmCmBgYAoKIyMgQ29tYmluZSBNdVRlY3QyIGFuZCBTdHJlbGthMiBkYXRhLmZyYW1lcyBpbnRvIG9uZSBkYXRhLmZyYW1lCgpTYXZlIHRvIGEgVFNWIGZpbGUuCgpgYGB7cn0KIyBNZXJnZSB0aGVzZSBkYXRhLmZyYW1lcyB0b2dldGhlcgp2YWZfZGYgPC0gc3RyZWxrYTJfdmFmICU+JQogIGRwbHlyOjpmdWxsX2pvaW4obXV0ZWN0Ml92YWYsIGJ5ID0gJ211dGF0aW9uX2lkJywgCiAgICAgICAgICAgICAgICAgICAgc3VmZml4ID0gYygiLnN0cmVsa2EyIiwgIi5tdXRlY3QyIikpICU+JQogICMgTWFrZSBhIHZhcmlhYmxlIHRoYXQgZGVub3RlcyB3aGljaCBkYXRhc2V0IGl0IGlzIGluLgogIGRwbHlyOjptdXRhdGUoZGF0YXNldCA9IGRwbHlyOjpjYXNlX3doZW4oIAogICAgaXMubmEoQWxsZWxlLm11dGVjdDIpIH4gInN0cmVsa2EyX29ubHkiLAogICAgaXMubmEoQWxsZWxlLnN0cmVsa2EyKSB+ICJtdXRlY3QyX29ubHkiLCAKICAgIFRSVUUgfiAiYm90aCIpKSAlPiUKICByZWFkcjo6d3JpdGVfdHN2KGZpbGUucGF0aCgicmVzdWx0cyIsICJjb21iaW5lZF9yZXN1bHRzLnRzdiIpKQpgYGAKClNlc3Npb24gSW5mbzogCgpgYGB7cn0Kc2Vzc2lvbkluZm8oKQpgYGAK